﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace SetNet.Client
{
    abstract public class Client
    {
        Socket client;
        IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
        IPEndPoint localEndPoint;

        byte[] check;
        Timer timer;
        public Client()
        {

        }

        public void StartClient(string host, int port)
        {
            try
            {
                
                IPAddress ipAddress;
                ipAddress = IPAddress.Parse(host);
                localEndPoint = new IPEndPoint(ipAddress, port);
                if (Configuration.type == (byte)Configuration.socketType.tcp)
                {
                    client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    client.NoDelay = Configuration.noDelay;
                    client.Connect(localEndPoint);
                }
                if (Configuration.type == (byte)Configuration.socketType.udp)
                {
                    client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    client.Connect(localEndPoint);
                    check = Encoding.UTF8.GetBytes("TimeOUT");
                    Log("Lenght: "+check.Length.ToString());
                    timer = new Timer(CheckTimeOut);
                    timer.Change(0, 1000);
                    if (client.Connected)
                    {
                        byte[] login = new byte[3];
                        login = Encoding.UTF8.GetBytes("1");
                        client.Send(login);
                    }
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine("Could't connect to the server or server was shutdown. Error: " + ex);
            }
        }


        void Connect(IPEndPoint endPoint)
        {
            client.Close();
            try
            {
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                client.Connect(endPoint);
            }
            catch (SocketException ex)
            {
                Connect(endPoint);
            }
        }

        private void CheckTimeOut(object state)
        {
            client.Send(check);
        }

        

        public void StartReceive()
        {
            Thread receivethread = new Thread(ReceiveThread);
            receivethread.IsBackground = true;
            receivethread.Start();
        }

        void ReceiveThread()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[Configuration.bufferLenght];
                    int read = client.Receive(buffer);
                    if (read > 0)
                    {
                        EventData data = Serialization.Deserializate(buffer);
                        if (data != null)
                        {
                            RecevieData(data);
                        }
                    }
                }
                catch (Exception ex)
                {
                    
                    Console.WriteLine("Could't connect to the server or server was shutdown. Error: " + ex);
                    Connect(localEndPoint);
                    
                }

            }
        }
        

        public void Update()
        {
            if (client.Available > 0)
            {
                byte[] buffer = new byte[Configuration.bufferLenght];
                int read = client.Receive(buffer);
                if (read > 0)
                {
                    EventData data = Serialization.Deserializate(buffer);
                    if (data != null)
                    {
                        RecevieData(data);
                    }
                }
            }


        }

        public void SendEvent(EventData eventData)
        {
            byte[] buf = Serialization.Serializate(eventData);
            try
            {
                if (Configuration.type == (byte)Configuration.socketType.tcp)
                    client.Send(buf);
                if (Configuration.type == (byte)Configuration.socketType.udp)
                    client.Send(buf);
            }
            catch (SocketException ex)
            {
                Console.WriteLine("Could't connect to the server or server was shutdown. Error: " + ex);
                Connect(localEndPoint);
            }
        }

        abstract public void RecevieData(EventData eventData);

        public abstract void Log(string text);

    }
}
